package cn.goour.web.sys.service

import cn.goour.utils.http.Http
import cn.goour.utils.http.HttpConfig
import cn.goour.web.sys.entity.Log
import cn.goour.web.sys.entity.User
import cn.goour.web.sys.entity.UserLoginAuthorize
import cn.goour.web.sys.entity.type.ActionType
import cn.goour.web.sys.entity.type.LoginType
import cn.goour.web.sys.repository.LogRepository
import cn.goour.web.sys.repository.UserLoginAuthorizeRepository
import cn.goour.web.sys.repository.UserRepository
import com.alibaba.fastjson.JSONObject
import com.qq.connect.QQConnectException
import com.qq.connect.api.OpenID
import com.qq.connect.api.qzone.UserInfo
import getUser
import org.apache.commons.lang3.StringUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes
import weibo4j.model.WeiboException
import java.net.URLEncoder
import javax.security.auth.login.LoginException
import javax.servlet.http.HttpServletRequest
import javax.transaction.Transactional

@Service
@Transactional
open class UserLoginService {
    @Autowired private
    lateinit var userRepository: UserRepository
    @Autowired private
    lateinit var logRepository: LogRepository
    @Autowired private
    lateinit var authorizeRepository: UserLoginAuthorizeRepository

    init {
        logger.info("initialized ...")
    }

    @Throws(WeiboException::class)
    open fun getLogin(token: weibo4j.http.AccessToken): User {
        logger.info("微博登陆方式================================" + token)
        val request = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).request
        val session = request.session

        var authorize: UserLoginAuthorize? = authorizeRepository.getByIdentifierAndLoginType(token.uid, LoginType.WeiBo)
        return when {
            authorize != null -> {
                // 登录成功，并且系统中已经存在该账户
                authorize.credential = token.accessToken

                flushLoginInfo(authorize, request)
            }
            session.getAttribute("user") != null -> {
                // 这是一个已登录用户，为其绑定新的登录方式
                val user = request.getUser()
                authorize = UserLoginAuthorize(token, request)

                addLoginType(user, authorize)
            }
            else -> {
                // 登录成功，但是系统中没有该用户，这是一个新的用户
                val um = weibo4j.Users(token.accessToken)
                val sitesUser = um.showUserById(token.uid)
                logger.info("注册-从服务器获得的用户信息：" + sitesUser)

                val user = User(sitesUser)
                authorize = UserLoginAuthorize(token, request)

                newLoginType(user, authorize)
            }
        }
    }

    @Throws(QQConnectException::class)
    open fun getLogin(token: com.qq.connect.javabeans.AccessToken): User {
        logger.info("QQ登录方式============================" + token)
        val openIDObj = OpenID(token.accessToken)
        val openID = openIDObj.userOpenID

        val request = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).request
        val session = request.session

        var authorize: UserLoginAuthorize? = authorizeRepository.getByIdentifierAndLoginType(openID, LoginType.QQ)
        return when {
            authorize != null -> {
                // 登录成功，并且系统中已经存在该账户
                authorize.credential = token.accessToken

                flushLoginInfo(authorize, request)
            }
            session.getAttribute("user") != null -> {
                // 这是一个已登录用户，为其绑定新的登录方式
                val user = request.getUser()
                authorize = UserLoginAuthorize(token, openID, request)

                addLoginType(user, authorize)
            }
            else -> {
                // 登录成功，但是系统中没有该用户，这是一个新的用户
                val qzoneUserInfo = UserInfo(token.accessToken, openID)
                val sitesUser = qzoneUserInfo.userInfo
                logger.info("注册-从服务器获取的数据：" + sitesUser)

                val user = User(sitesUser)
                authorize = UserLoginAuthorize(token, openID, request)

                newLoginType(user, authorize)
            }
        }
    }

    @Throws(Exception::class)
    open fun getLogin(token: cn.yiban.open.common.entity.AccessToken): User {
        logger.info("易班登录方式==============================" + token)
        val request = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).request
        val session = request.session

        var authorize: UserLoginAuthorize? = authorizeRepository.getByIdentifierAndLoginType(token.userid, LoginType.YiBan)
        logger.info("登录时查询数据库结果：" + authorize)

        return when {
            authorize != null -> {
                // 登录成功，并且系统中已经存在该账户
                authorize.credential = token.access_token

                flushLoginInfo(authorize, request)
            }
            session.getAttribute("user") != null -> {
                // 这是一个已登录用户，为其绑定新的登录方式
                val user = request.getUser()
                authorize = UserLoginAuthorize(token, request)

                addLoginType(user, authorize)
            }
            else -> {
                // 登录成功，但是系统中没有该用户，这是一个新的用户
                val sitesUserAction = cn.yiban.open.common.User(token.access_token)
                val sitesUser = cn.yiban.open.common.entity.User.parseJsonObject(JSONObject.parseObject(sitesUserAction.me()))
                if (sitesUser.status == "success") {
                    logger.info("注册-从服务器返回的数据：" + sitesUser)

                    val user = User(sitesUser)
                    authorize = UserLoginAuthorize(token, request)

                    newLoginType(user, authorize)
                } else {
                    // 获取信息出现错误
                    throw LoginException(sitesUser.userInfo.msgCN)
                }
            }
        }
    }

    @Throws(Exception::class)
    open fun getLogin(token: com.qq.weixin.open.entity.AccessToken): User {
        logger.info("微信登录方式==============================" + token)
        val request = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).request
        val session = request.session
        val identifier = if (StringUtils.isNotEmpty(token.unionid)) {
            token.unionid
        } else {
            token.openid
        }

        var authorize: UserLoginAuthorize? = authorizeRepository.getByIdentifierAndLoginType(identifier, LoginType.WeiXin)
        logger.info("登录时查询数据库结果：" + authorize)

        return when {
            authorize != null -> {
                // 登录成功，并且系统中已经存在该账户
                authorize.credential = token.access_token

                flushLoginInfo(authorize, request)
            }
            session.getAttribute("user") != null -> {
                // 这是一个已登录用户，为其绑定新的登录方式
                val user = request.getUser()

                authorize = UserLoginAuthorize(token, request)

                addLoginType(user, authorize)
            }
            StringUtils.containsIgnoreCase(session.getAttribute("weixin.scope"), "snsapi_userinfo") -> {// 微信登录只有请求方式为snsapi_userinfo才能通过接口获取到用户信息
                // 登录成功，但是系统中没有该用户，这是一个新的用户
                val url = "https://api.weixin.qq.com/sns/userinfo?access_token=${URLEncoder.encode(token.access_token, "utf-8")}&openid=${URLEncoder.encode(token.openid, "utf-8")}&lang=zh_CN"
//                val userStr = HTTPSimple.GET(url) // 本来我是想用这种方法的，结果它返回的中文有乱码无法正常阅读和解析，然后就蛋疼了
                val re = Http.get(HttpConfig(url))

                val sitesUser = com.qq.weixin.open.entity.User.parseJsonObject(JSONObject.parseObject(String(re)))
                if (sitesUser.errcode == 0) {
                    logger.info("注册-从服务器返回的数据：" + sitesUser)

                    val user = User(sitesUser)
                    authorize = UserLoginAuthorize(token, request)

                    newLoginType(user, authorize)
                } else {
                    // 获取信息出现错误
                    throw LoginException(sitesUser.errmsg)
                }
            }
            else -> {// 一种没办法获取到用户信息的登录，我们将为其创建一个默认的账户信息

                val user = User(nick = "游客")
                authorize = UserLoginAuthorize(token, request)

                newLoginType(user, authorize)
            }
        }
    }

    private fun flushLoginInfo(authorize: UserLoginAuthorize, request: HttpServletRequest): User {
        logger.info("登录成功，并且系统中已经存在该账户：" + authorize)
        val type = authorize.loginType
        val log = Log(authorize.user, ActionType.Login, "${type.text} ${ActionType.Login.text}", request)
        logRepository.save(log)
        val re = authorizeRepository.saveAndFlush(authorize)
        return validCanLogin(re.user)
    }

    private fun addLoginType(user: User, authorize: UserLoginAuthorize): User {
        return saveLoginType(authorize, user, ActionType.AddLoginType, "${ActionType.AddLoginType.text} ${authorize.loginType.text}")
    }

    private fun newLoginType(user: User, authorize: UserLoginAuthorize): User {
        return saveLoginType(authorize, user, ActionType.Register, "通过 ${authorize.loginType.text} 登陆，自动注册用户")
    }

    private fun saveLoginType(authorize: UserLoginAuthorize, user: User, actionType: ActionType, actionText: String): User {

        val log = Log(user, actionType, actionText, authorize.request)
        logRepository.save(log)

        user.authorizes = user.authorizes.plus(authorize)
        return validCanLogin(userRepository.saveAndFlush(user))
    }

    private fun validCanLogin(user: User?): User {
        if (user != null) {
            if (user.login) {
                return user
            }
        } else {
            logger.info("帐号错误")
        }
        throw LoginException("帐号不允许登录")
    }

    companion object {
        private val logger = LoggerFactory.getLogger(UserLoginService::class.java)
    }
}
